﻿using IPlugins;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;

namespace PluginHost
{
    public class PluginFunc
    {
        //private static readonly Lazy<PluginFunc> _lazy = new Lazy<PluginFunc>(() => new PluginFunc());
        //private PluginFunc() { }
        //public static PluginFunc Instance => _lazy.Value;

        public PluginHost pluginHost { get; set; }

        public PluginFunc(PluginHost _pluginHost)
        {
            pluginHost = _pluginHost;
        }

        #region func
        public void InitializePluginSystem()
        {
            RegisterFunction();
            LoadPlugins();
            RefreshPluginMenu();
        }

        public void RegisterFunction()
        {
            // 注册宿主函数，暴露这些函数给插件调用
            pluginHost.RegisterFunction("GetMainFormTitle", new Func<string>(() => pluginHost.MainForm.Text));
            pluginHost.RegisterFunction("ShowHostMessage", new Action<string>(msg => MessageBox.Show(msg, "pluginHost Message")));
        }

        public void RefreshPluginMenu()
        {
            MenuStrip menuStrip = null;
            ToolStripMenuItem _pluginsMenu = null;

            menuStrip = pluginHost.MainForm.Controls.OfType<MenuStrip>().FirstOrDefault();
            if(menuStrip == null)
                menuStrip = new MenuStrip();
            _pluginsMenu = pluginHost.MainForm.Controls.OfType<ToolStripMenuItem>().FirstOrDefault(t => t.Text == "插件");
            if (_pluginsMenu == null)
                _pluginsMenu = new ToolStripMenuItem("插件");

            foreach (var plugin in pluginHost.Plugins)
            {
                var pluginItem = new ToolStripMenuItem(plugin.Name)
                {
                    Tag = plugin,
                    Checked = plugin.IsEnabled
                };

                // 启用/禁用插件
                pluginItem.Click += (s, e) => TogglePluginEnabled(pluginItem);

                // 添加配置子菜单
                //var configItem = new ToolStripMenuItem("设置");
                //configItem.Click += (s, e) =>
                //    pluginHost.ShowPluginConfig(plugin.Name);
                //pluginItem.DropDownItems.Add(configItem);

                _pluginsMenu.DropDownItems.Add(pluginItem);
                menuStrip.Items.Add(_pluginsMenu);
            }
        }

        public void TogglePluginEnabled(ToolStripMenuItem pluginItem)
        {
            var plugin = pluginItem.Tag as IPlugins.IPlugin;
            bool newState = !plugin.IsEnabled;

            SetPluginEnabled(plugin.Name, newState);
            pluginItem.Checked = newState;
        }


        public void AddNewPlugin()
        {
            using (var openDialog = new OpenFileDialog())
            {
                openDialog.Filter = "Plugin Assemblies (*.dll)|*.dll";
                openDialog.Title = "Select Plugin Assembly";
                openDialog.Multiselect = false;

                if (openDialog.ShowDialog() == DialogResult.OK)
                {
                    var config = new PluginConfig
                    {
                        AssemblyPath = openDialog.FileName,
                        Enabled = true
                    };

                    AddPluginConfig(config);
                    RefreshPluginMenu();
                }
            }
        }

        public void AddPluginConfig(PluginConfig config)
        {
            pluginHost.PluginConfigs.Add(config);
            SavePluginConfigs();
            LoadPluginAssembly(config.AssemblyPath);
        }

        public void RefreshPlugins()
        {
            foreach (var plugin in pluginHost.Plugins)
            {
                if (plugin.IsEnabled)
                {
                    plugin.Shutdown();
                }
            }
            RefreshPluginMenu();
        }

        public List<PluginConfig> LoadPluginConfigs(string pluginsDir)
        {
            var configFile = Path.Combine(pluginsDir, "plugins.config.json");
            if (!File.Exists(configFile))
                return new List<PluginConfig>();

            try
            {
                var json = File.ReadAllText(configFile);
                return Newtonsoft.Json.JsonConvert.DeserializeObject<List<PluginConfig>>(json) ?? new List<PluginConfig>();
            }
            catch (Exception ex)
            {
                MessageBox.Show($"Failed to load plugin config: {ex.Message}", "Error");
                return new List<PluginConfig>();
            }
        }

        public void LoadPluginConfigs()
        {
            var configFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "plugins.config.json");
            if (File.Exists(configFile))
            {
                try
                {
                    var json = File.ReadAllText(configFile);
                    pluginHost.PluginConfigs = JsonConvert.DeserializeObject<List<PluginConfig>>(json) ?? new List<PluginConfig>();
                }
                catch (Exception ex)
                {
                    MessageBox.Show(string.Format("Failed to load plugin configurations: {0}", ex.Message));
                }
            }
            else
            {
                //默认配置
                pluginHost.PluginConfigs.Add(new PluginConfig
                {
                    Name = "SamplePlugin",
                    AssemblyPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "SamplePlugin.dll"),
                    Enabled = true,
                    Settings = new Dictionary<string, object> { { "ConfigValue", "Default" } }
                });
                SavePluginConfigs();
            }
        }

        public void SavePluginConfigs()
        {
            var configFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "plugins.config.json");
            try
            {
                var json = JsonConvert.SerializeObject(pluginHost.PluginConfigs, Newtonsoft.Json.Formatting.Indented);
                File.WriteAllText(configFile, json);
            }
            catch (Exception ex)
            {
                MessageBox.Show(string.Format("Failed to save plugin configurations: {0}", ex.Message));
            }
        }

        public void LoadPlugins()
        {
            LoadPluginConfigs();
            foreach (var config in pluginHost.PluginConfigs.Where(c => c.Enabled))
            {
                LoadPluginAssembly(config.AssemblyPath);
            }
        }

        public void LoadPluginAssembly(string assemblyPath)
        {
            try
            {
                var assembly = Assembly.LoadFrom(assemblyPath);
                var pluginTypes = assembly.GetTypes()
                    .Where(t => typeof(IPlugins.IPlugin).IsAssignableFrom(t) && !t.IsAbstract);

                foreach (var type in pluginTypes)
                {
                    var plugin = (IPlugins.IPlugin)Activator.CreateInstance(type);
                    var config = pluginHost.PluginConfigs.FirstOrDefault(c => c.AssemblyPath.Equals(assemblyPath, StringComparison.OrdinalIgnoreCase));

                    plugin.IsEnabled = config != null ? config.Enabled : true;
                    plugin.Initialize(pluginHost);
                    pluginHost.Plugins.Add(plugin);

                    //if (plugin.IsEnabled)
                    //{
                    //    plugin.Execute();
                    //}
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(string.Format("Failed to load plugin from {0}: {1}", assemblyPath, ex.Message));
            }
        }

        public void SetPluginEnabled(string pluginName, bool enabled)
        {
            var plugin = pluginHost.Plugins.FirstOrDefault(p => p.Name == pluginName);
            if (plugin == null) return;

            if (plugin.IsEnabled && !enabled)
            {
                plugin.Shutdown();
            }

            plugin.IsEnabled = enabled;

            if (enabled)
            {
                plugin.Execute();
            }

            var config = pluginHost.PluginConfigs.FirstOrDefault(c =>
                c.AssemblyPath.EndsWith(string.Format("{0}.dll", pluginName), StringComparison.OrdinalIgnoreCase));

            if (config != null)
            {
                config.Enabled = enabled;
                SavePluginConfigs();
            }
        }

        #region 插件配置支持
        public void ShowPluginConfiguration(string pluginName)
        {
            var plugin = pluginHost.Plugins.FirstOrDefault(p => p.Name == pluginName);
            if (plugin == null) return;

            var configurablePlugin = plugin as IPluginConfiguration;
            if (configurablePlugin == null)
            {
                MessageBox.Show("This plugin does not support configuration.");
                return;
            }

            var configDialog = new Form
            {
                Text = string.Format("{0} Configuration", pluginName),
                Size = new System.Drawing.Size(500, 400),
                StartPosition = FormStartPosition.CenterParent,
                FormBorderStyle = FormBorderStyle.FixedDialog
            };

            var configControl = configurablePlugin.GetConfigurationControl();
            if (configControl == null)
            {
                MessageBox.Show("This plugin has no configuration interface.");
                return;
            }

            configControl.Dock = DockStyle.Fill;
            configDialog.Controls.Add(configControl);

            var btnSave = new Button { Text = "Save", Dock = DockStyle.Bottom };
            btnSave.Click += (s, e) =>
            {
                configurablePlugin.SaveConfiguration();

                // 更新配置
                var config = pluginHost.PluginConfigs.FirstOrDefault(c => c.AssemblyPath.EndsWith(string.Format("{0}.dll", pluginName), StringComparison.OrdinalIgnoreCase));

                if (config != null)
                {
                    SavePluginConfigs();
                }

                configDialog.DialogResult = DialogResult.OK;
            };

            configDialog.Controls.Add(btnSave);
            configDialog.ShowDialog();
        }
        #endregion



        #endregion


    }
}
